#include "IEC_asduDecoder.h"
#include <string.h>

using namespace XIEC;


bool CAsduDecoder::decode(const xuint8* frame, xuint8 len, DataUnitTag& dataUnit, CVectInfoObject& infoObjects, const Settings &setting)
{
    xuint8 pos = 0;
    if (len >= 3) {
        dataUnit.typeId = frame[pos++];
        dataUnit.vsq.d  = frame[pos++];
        dataUnit.cot8[0] = frame[pos++];
    }
    if (setting.cot_len != 1 && pos<len)
        dataUnit.cot8[1] = frame[pos++];
    if (pos < len) {
        dataUnit.ca8[0] = frame[pos++];
        if (setting.coa_len != 1 && pos<len)
            dataUnit.ca8[1] = frame[pos++];
    }
    return asduDecode(frame+pos, len-pos, dataUnit.typeId, dataUnit.vsq, infoObjects, setting);
}

bool CAsduDecoder::asduDecode(const xuint8* frame, xuint8 len, xuint8 typeId, VSQ vsq, CVectInfoObject& infoObjects, const Settings &settings)
{
    xuint8 pos = 0;
    xuint8 addrLen = settings.info_obj_addr_len;
    xuint32 addr0 = 0;
    for(xuint8 i = 0; i < vsq.cnt; i++) {
        CInfoObject* info = newInfoObject(typeId);
        if (info != 0 && pos+addrLen+info->length() <= len) {
            if (vsq.SQ == 0) {
                memcpy(info->addr().addr, frame+pos, addrLen);
                pos += addrLen;
            }
            else {
                if (i == 0) {
                    memcpy(info->addr().addr, frame, addrLen);
                    pos += addrLen;
                    addr0 = info->addr().d;
                }
                else {
                    info->addr().d = addr0+i;
                }
            }
            if (info->length()) {
                memcpy(info->data(), frame+pos, info->length());
                pos+=info->length();
            }
            infoObjects.push_back(info);
        }
        else {
            delete info;
            return false;
        }
    }
    return true;
}


CInfoObject* CAsduDecoder::newInfoObject(xuint8 typeId)
{
    switch(typeId) {
    case 45:
        return new CInfoObject45();
    case 46:
        return new CInfoObject46();
    case 47:
        return new CInfoObject47();
    case 48:
        return new CInfoObject48();
    case 49:
        return new CInfoObject49();
    case 50:
        return new CInfoObject50();
    case 51:
        return new CInfoObject51();
    case 100:
        return new CInfoObject100();
    case 101:
        return new CInfoObject101();
    case 102:
        return new CInfoObject102();
    case 103:
        return new CInfoObject103();
    case 104:
        return new CInfoObject104();
    case 105:
        return new CInfoObject105();
    case 106:
        return new CInfoObject106();
    case 110:
        return new CInfoObject110();
    case 111:
        return new CInfoObject111();
    case 112:
        return new CInfoObject112();
    case 113:
        return new CInfoObject113();
    case 1 :
        return new CInfoObject1();
    case 2:
        return new CInfoObject2();
    case 3:
        return new CInfoObject3();
    case 4:
        return new CInfoObject4();
    case 5:
        return new CInfoObject5();
    case 6:
        return new CInfoObject6();
    case 7:
        return new CInfoObject7();
    case 8:
        return new CInfoObject8();
    case 9:
        return new CInfoObject9();
    case 10:
        return new CInfoObject10();
    case 11:
        return new CInfoObject11();
    case 12:
        return new CInfoObject12();
    case 13:
        return new CInfoObject13();
    case 14:
        return new CInfoObject14();
    case 15:
        return new CInfoObject15();
    case 16:
        return new CInfoObject16();
    case 17:
        return new CInfoObject17();
    case 18:
        return new CInfoObject18();
    case 19:
        return new CInfoObject19();
    case 20:
        return new CInfoObject20();
    case 21:
        return new CInfoObject21();
    case 30:
        return new CInfoObject30();
    case 31:
        return new CInfoObject31();
    case 32:
        return new CInfoObject32();
    case 33:
        return new CInfoObject33();
    case 34:
        return new CInfoObject34();
    case 35:
        return new CInfoObject35();
    case 36:
        return new CInfoObject36();
    case 37:
        return new CInfoObject37();
    case 38:
        return new CInfoObject38();
    case 39:
        return new CInfoObject39();
    case 40:
        return new CInfoObject40();
    case 70:
        return new CInfoObject70();
    default:
        break;
    }

    return 0;
}
